﻿using PlutoStudio.Modules;
using System;
using System.Collections.Generic;
using System.Text;
using PlutoStudio.Dependency;
using PlutoStudio.EF.UnitOfWork;
using PlutoStudio.Reflection;
using PlutoStudio.EF.Configuration;
using System.Reflection;
using Autofac;
using PlutoStudio.EF.Repositories;

namespace PlutoStudio.EF
{
    public sealed class EntityFrameworkModule : Modules.Module
    {
        public EntityFrameworkModule(ITypeFinder typeFinder) 
        {
            _typeFinder = typeFinder;
        }

        private readonly ITypeFinder _typeFinder;

        public override void PreInitialize()
        {
            IocManager.Register<IEfConfiguration, EfConfiguration>();
            //IocManager.RegisterGeneric(typeof(DbContextConfigurerAction<>), typeof(IDbContextConfigurer<>), LifetimeScopeStyle.Transient);
            //IocManager.Register<IEfGenericRepositoryRegistrar, EfGenericRepositoryRegistrar>(LifetimeScopeStyle.Transient);
        }

        public override void Initialize()
        {
            IocManager.RegisterAssemblyByConvention(typeof(EntityFrameworkModule).Assembly);
            IocManager.RegisterGeneric(typeof(IDbContextProvider<>), typeof(UnitOfWorkDbContextProvider<>), LifetimeScopeStyle.Transient);
            RegisterGenericRepositoriesAndMatchDbContexes();
        }

        private void RegisterGenericRepositoriesAndMatchDbContexes()
        {
            var dbContextTypes =
                _typeFinder.Find(type =>
                {
                    var typeInfo = type.GetTypeInfo();
                    return typeInfo.IsPublic &&
                           !typeInfo.IsAbstract &&
                           typeInfo.IsClass &&
                           typeof(FrameworkDbContext).IsAssignableFrom(type);
                });

            if (dbContextTypes.IsNullOrEmpty())
            {
                Logger.Warn("No class found derived from FrameworkDbContext.");
                return;
            }

            using (var scope = IocManager.CreateScope())
            {
                foreach (var dbContextType in dbContextTypes)
                {
                    Logger.Debug("Registering DbContext: " + dbContextType.AssemblyQualifiedName);

                    scope.Resolve<IEfGenericRepositoryRegistrar>().RegisterForDbContext(dbContextType, IocManager, EfAutoRepositoryTypes.Default);
                }

                scope.Resolve<IDbContextTypeMatcher>().Populate(dbContextTypes);
            }
        }
    }
}
